#include <string.h>
#include <iostream>

using std::cout;
using std::endl;

class String
{
public:
    String();
    String(const char * );
    String(const String &);
    String & operator=(const String &);
    ~String();


    //当类中同时都有这两组函数时，具有移动语义的函数会优先调用

    //右值引用可以确定传递过来的是右值
    //那就可以执行移动操作了
    //称为移动构造函数
    String(String && rhs)
    : _pstr(rhs._pstr) //浅拷贝
    {
        cout << "String(String &&)" << endl;
        rhs._pstr = nullptr;//修改右值中的指向
    }

    //称为移动赋值运算符函数
    String & operator=(String && rhs)
    {   //rhs在函数栈空间中是左值，可以取地址
        cout << "String & operator=(String &&)" << endl;
        if(this != &rhs) {//防止自移动
            delete [] _pstr;
            _pstr = rhs._pstr;//浅拷贝
            rhs._pstr = nullptr;//修改右值的指向
        }
        return *this;
    }

    void print() const;

    const char * c_str() const {    return _pstr;   }

    size_t length() const { 
        //当传递空指针过来时，strlen会直接崩溃
        if(_pstr) {
            return strlen(_pstr);
        }
        return 0;
    }


    friend std::ostream & operator<<(std::ostream & os, const String & rhs);

private:
    char * _pstr;
};

std::ostream & operator<<(std::ostream & os, const String & rhs)
{
    if(rhs._pstr)
        os << rhs._pstr;
    return os;
}

String::String()
    : _pstr(nullptr)
{   
    cout << "String()" << endl; 
}

String::String(const char * pstr)
    : _pstr(new char[strlen(pstr) + 1]())
{
    cout << "String(const char*)" << endl;
    strcpy(_pstr, pstr);
}

String::String(const String & rhs)
    : _pstr(new char[strlen(rhs._pstr) + 1]())
{
    cout << "String(const String &)" << endl;
    strcpy(_pstr, rhs._pstr);
}

String & String::operator=(const String & rhs)
{
    cout << "operator=(const String&)" << endl;
    if(this != &rhs) {
        delete [] _pstr;
        _pstr = new char[strlen(rhs._pstr) + 1]();
        strcpy(_pstr, rhs._pstr);
    }
    return *this;
}

void String::print() const
{   
    //char* 的nullptr，由cout进行输出时，会导致程序直接崩溃
    //而且还没有报错信息
    if(_pstr) {
        cout << _pstr << endl;  
    }
}

String::~String()
{
    cout << "~String()" << endl;
    delete [] _pstr;
    _pstr = nullptr;
}

String && func()
{
    return String("aaaa");
}

void test0()
{
    //&String("world");//临时对象存在的生命周期很短
    String str1 = String("hello");//调用移动构造函数

    //String str2("world");

    //&str2;//可以取地址, 是左值
    //右值引用无法绑定到左值
    //String && ref = str2;//error
    //右值引用只能够绑定到右值, 在语法层面可以单独识别出右值了
    String && ref2 = String("hello");
    &ref2;//ok 右值引用本身有名字的情况下，可以取地址, 是左值
    cout << " 111"  << endl;
    
    //ref2虽然是右值引用，但此时是左值
    //以下这一句调用的是拷贝构造函数
    String str2 = ref2;

    cout << "-----" << endl;

    //&func();//error  不能取地址,返回值是右值引用，但是一个右值
}

void test1()
{
    String str1("wangdao");
    str1 = String("hello");//调用移动赋值运算符函数
    cout << "str1:" << str1 << endl;

    cout << " -----" << endl;

    //str1本身是左值，但通过std::move函数的作用之后，
    //可以显式将左值强制转换为右值
    String str2 = std::move(str1);
    //str1 = str1;
    cout << "str1:" << str1 << endl;
    cout << "str2:" << str2 << endl;

    str2 = std::move(str2);//自移动
}


String func2()
{
    //在同时定义了具有移动语义和复制语义的函数时，
    //如果发现return的对象即将被销毁,那就调用移动构造函数
    String s1("world");
    cout << "s1:" << s1 << endl;
    return s1;
}

String gstr("bbbbbb");

String func3()
{
    //在同时定义了具有移动语义和复制语义的函数时，
    //如果发现return的对象其生命周期大于函数，
    //那就调用拷贝构造函数
    cout << "gstr:" << gstr << endl;
    return gstr;
}

void test2()
{
    func2();
    cout << endl;
    func3();
}

int main()
{
    /* test0(); */
    /* test1(); */
    test2();
    return 0;
}

